package com.yupi.springbootinit.statemachine.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 状态机核心引擎
 * 线程安全的状态转换处理器
 */
@Slf4j
@Component
public class StateMachine {
    
    /**
     * 状态转换规则映射
     * Key: StateType, Value: 转换规则映射
     */
    private final Map<String, Map<String, List<String>>> transitionRules = new ConcurrentHashMap<>();
    
    /**
     * 状态处理器映射
     * Key: StateType, Value: 处理器列表
     */
    private final Map<String, List<StateProcessor<?, ?>>> processors = new ConcurrentHashMap<>();
    
    /**
     * 实体锁映射，确保同一实体的状态转换串行化
     */
    private final Map<String, ReentrantLock> entityLocks = new ConcurrentHashMap<>();
    
    /**
     * 注册状态转换规则
     * @param stateType 状态类型
     * @param fromState 源状态
     * @param toStates 可转换的目标状态列表
     */
    public void registerTransition(String stateType, String fromState, List<String> toStates) {
        transitionRules.computeIfAbsent(stateType, k -> new ConcurrentHashMap<>())
                      .put(fromState, toStates);

    }
    
    /**
     * 注册状态处理器
     * @param processor 状态处理器
     */
    public void registerProcessor(StateProcessor<?, ?> processor) {
        String stateType = processor.getSupportedStateType();
        processors.computeIfAbsent(stateType, k -> new java.util.ArrayList<>())
                  .add(processor);
        log.info("注册状态处理器: {} -> {}", stateType, processor.getClass().getSimpleName());
    }
    
    /**
     * 执行状态转换
     * @param context 状态上下文
     * @return 转换结果
     */
    public TransitionResult transition(StateContext context) {
        long startTime = System.currentTimeMillis();
        String lockKey = context.getEntityType() + ":" + context.getEntityId();
        ReentrantLock lock = entityLocks.computeIfAbsent(lockKey, k -> new ReentrantLock());
        
        lock.lock();
        try {
            // 验证状态转换是否合法
            if (!isValidTransition(context)) {
                return TransitionResult.failure(
                    "INVALID_TRANSITION",
                    String.format("不允许从状态 %s 转换到 %s", 
                        context.getCurrentState().getCode(), 
                        context.getTargetState().getCode()),
                    context.getCurrentState(),
                    context.getEvent()
                );
            }
            
            // 执行前置处理
            List<StateProcessor<?, ?>> stateProcessors = processors.get(context.getCurrentState().getStateType());
            if (stateProcessors != null) {
                for (StateProcessor<?, ?> processor : stateProcessors) {
                    try {
                        if (!processor.beforeTransition(context)) {
                            return TransitionResult.failure(
                                "BEFORE_TRANSITION_FAILED",
                                "前置处理器阻止了状态转换",
                                context.getCurrentState(),
                                context.getEvent()
                            );
                        }
                    } catch (Exception e) {
                        log.error("前置处理器执行失败", e);
                        processor.onTransitionError(context, e);
                        return TransitionResult.failure(
                            "BEFORE_TRANSITION_ERROR",
                            "前置处理器执行异常: " + e.getMessage(),
                            context.getCurrentState(),
                            context.getEvent()
                        );
                    }
                }
            }
            
            // 记录状态转换
            State fromState = context.getCurrentState();
            State toState = context.getTargetState();
            
            log.info("执行状态转换: 实体[{}:{}] {} -> {} 事件[{}] 操作人[{}]",
                context.getEntityType(), context.getEntityId(),
                fromState.getCode(), toState.getCode(),
                context.getEvent().getCode(), context.getOperatorName());
            
            // 执行后置处理
            if (stateProcessors != null) {
                for (StateProcessor<?, ?> processor : stateProcessors) {
                    try {
                        processor.afterTransition(context);
                    } catch (Exception e) {
                        log.error("后置处理器执行失败", e);
                        processor.onTransitionError(context, e);
                        // 后置处理失败不影响状态转换结果
                    }
                }
            }
            
            long duration = System.currentTimeMillis() - startTime;
            return TransitionResult.success(fromState, toState, context.getEvent(), duration);
            
        } finally {
            lock.unlock();
            // 清理长时间未使用的锁
            if (entityLocks.size() > 1000) {
                cleanupLocks();
            }
        }
    }
    
    /**
     * 验证状态转换是否合法
     */
    private boolean isValidTransition(StateContext context) {
        String stateType = context.getCurrentState().getStateType();
        String fromState = context.getCurrentState().getCode();
        String toState = context.getTargetState().getCode();
        
        Map<String, List<String>> typeRules = transitionRules.get(stateType);
        if (typeRules == null) {
            log.warn("未找到状态类型 {} 的转换规则", stateType);
            return false;
        }
        
        List<String> allowedStates = typeRules.get(fromState);
        if (allowedStates == null) {
            log.warn("未找到状态 {} 的转换规则", fromState);
            return false;
        }
        
        return allowedStates.contains(toState);
    }
    
    /**
     * 清理长时间未使用的锁
     */
    private void cleanupLocks() {
        entityLocks.entrySet().removeIf(entry -> {
            ReentrantLock lock = entry.getValue();
            return !lock.isLocked() && lock.getQueueLength() == 0;
        });
    }
    
    /**
     * 获取指定状态类型的所有转换规则
     */
    public Map<String, List<String>> getTransitionRules(String stateType) {
        return transitionRules.getOrDefault(stateType, new ConcurrentHashMap<>());
    }
}